package com.yzg.cas;

import java.math.BigDecimal;
import java.util.LinkedList;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author misterWei
 * @create 2020年05月24号:13点29分
 * @mailbox forcontinue@163.com
 */
public class AtomicBigdecimal {

    public static void main(String[] args) {
        BigdecimalAccount b  = new AtomicBigdecimalOpt(new BigDecimal("10000"));
        b.demo(b);
        System.out.println(b.get());
    }

interface BigdecimalAccount{

    BigDecimal get();

    void options(BigDecimal bigDecimal);

    default void demo(BigdecimalAccount bigdecimalAccount){
        // 测试 1000 并发量
        int threadNum = 1000;

        CyclicBarrier cyclicBarrier = new CyclicBarrier(threadNum);
        LinkedList<Thread> linkedList = new LinkedList();
        for (int i = 0; i < threadNum - 1; i++) {
            Thread thread = new Thread(() -> {
                try {
                    //模拟并发
                    cyclicBarrier.await();
                    bigdecimalAccount.options(new BigDecimal("10"));
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }, i + " thread");
            linkedList.addLast(thread);
        }
        linkedList.forEach(thread -> {
            thread.start();
        });
        linkedList.forEach(thread -> {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }
}

static class AtomicBigdecimalOpt implements BigdecimalAccount{

    final AtomicReference<BigDecimal> bigDecimal ;

    public AtomicBigdecimalOpt(BigDecimal balance) {
        this.bigDecimal = new AtomicReference<>(balance);
    }

    @Override
    public BigDecimal get() {
        return bigDecimal.get();
    }

    @Override
    public void options(BigDecimal bigDecimal) {
       //原子操作
        while (true){
            BigDecimal perv = this.bigDecimal.get();
            BigDecimal next = perv.subtract(bigDecimal);
            //原子操作
            if (this.bigDecimal.compareAndSet(perv,next)){
                break;
            }
        }
    }
}
}
